// HSS.Threading.MutexHelper.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       MutexHelper.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Threading
{
	#region Using Directives
	using System;
	using System.Security.AccessControl;
	using System.Threading;
	#endregion

	#region MutexHelper
	/// <summary>
	/// A helper class providing syncronous access across boundries
	/// </summary>
	/// <remarks>
	/// This mutex helper is intended to simplify locking access to a globally available resource and
	/// to syncronize that access. It requires a Name (Named Mutex), and sets the security on the
	/// Mutex itself to "All Users" so that mutliple applications/users can share synchorized access.
	/// It is not intended to provide security to the actual syncronized resource. That 
	/// is left the developer to ensure resources are not accessed by unathorized users.
	/// </remarks>
	/// <example>
	/// <code>
	/// using (MutexHelper mtx = new MutexHelper("Global Unique Name"))
	/// {
	///		if (mtx.Acquired)
	///		{
	///			// Perform logic here to access protected resource(s)
	///			// File.Write or Read
	///		}
	/// } // On Dispose releases the mutex
	/// </code>
	/// </example>
	public sealed class MutexHelper : IDisposable
	{
		#region Fields
		Mutex tempMutex;
		bool closed = false;
		#endregion

		#region Constructors
		/// <summary>
		/// Open or create the named Mutex and attempt to acquire
		/// </summary>
		/// <param name="MutexName">The name of the mutex to acquire</param>
		public MutexHelper(string MutexName)
			: this(MutexName, true, 0)
		{
		}
		/// <summary>
		/// Open or create a Named Mutex and attempt to acquire if requested
		/// </summary>
		/// <param name="MutexName">The name of the mutex to open or create</param>
		/// <param name="Acquire">Should we attempt to acquire the Mutex</param>
		/// <param name="WaitTime">If Acquire is true, the time in milliseconds to wait</param>
		/// <exception cref="ApplicationException">Acquire is true and WaitTime is less than -1</exception>
		/// <exception cref="UnauthorizedAccessException">Caller is not authorized to access, open or create the Named Mutex</exception>
		public MutexHelper(string MutexName, bool Acquire, int WaitTime)
		{
			if (Acquire && WaitTime < -1)
				throw new ApplicationException("Acquire is true and WaitTime is less than -1");

			MutexSecurity mtxSec = new MutexSecurity();
			MutexAccessRule mar =
				new MutexAccessRule("Users", MutexRights.FullControl, AccessControlType.Allow);
			mtxSec.AddAccessRule(mar);
			tempMutex = new Mutex(Acquire, MutexName, out _acquired, mtxSec);
			if (!_acquired && Acquire)
				_acquired = tempMutex.WaitOne(WaitTime, false);
		}
		#endregion

		#region Properties
		/// <summary>
		/// Do we currently own the mutex
		/// </summary>
		public bool Acquired
		{
			get
			{
				if (closed)
					throw new ObjectDisposedException("MutexHelper is disposed and cannot be accessed.");
				return _acquired;
			}
		} bool _acquired = false;
		#endregion

		#region IDisposable Members
		/// <summary>
		/// Release the Mutex
		/// </summary>
		public void Dispose()
		{
			closed = true;
			if (null != tempMutex && _acquired)
			{
				_acquired = false;
				try { tempMutex.ReleaseMutex(); tempMutex.Dispose(); }
				catch { }
			}
		}

		#endregion
	}
	#endregion
}